use std::{fmt::Display, num::{ParseFloatError, ParseIntError}, sync::PoisonError};


#[derive(Debug)]
pub enum WError {
    NetError(String),
    Stop,
    Empty,
    Path,
    Join,
    DataError(String),
    DataBaseError(String),
    ParseError(String),
    RunError(Vec<String>),
}

impl Display for WError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::DataError(v) | Self::NetError(v) | Self::DataBaseError(v) | Self::ParseError(v) => write!(f, "{}", v),
            Self::RunError(v) => write!(f, "{}", v.join("\n")),
            Self::Stop => write!(f, "Found error, stop"),
            Self::Empty => write!(f, "Empty data"),
            Self::Path => write!(f, "Path error"),
            Self::Join => write!(f, "Join error"),
        }
    }
}


impl<T> From<PoisonError<T>> for WError {
    fn from(value: PoisonError<T>) -> Self {
        Self::DataError(value.to_string())
    }
}


impl From<std::io::Error> for WError {
    fn from(value: std::io::Error) -> Self {
        Self::DataError(value.to_string())
    }
}

impl From<ParseFloatError> for WError {
    fn from(value: ParseFloatError) -> Self {
        WError::DataError(value.to_string())
    }
}

impl From<ParseIntError> for WError {
    fn from(value: ParseIntError) -> Self {
        WError::DataError(value.to_string())
    }
}

#[cfg(feature = "zi")]
impl From<zip::result::ZipError> for WError {
    fn from(value: zip::result::ZipError) -> Self {
        Self::DataError(value.to_string())
    }
}


#[cfg(feature = "ser")]
impl From<serde_json::Error> for WError {
    fn from(value: serde_json::Error) -> Self {
        Self::DataError(value.to_string())
    }
}

#[cfg(feature = "encrypt")]
impl From<aes_gcm::Error> for WError {
    fn from(value: aes_gcm::Error) -> Self {
        Self::ParseError(value.to_string())
    }
}


impl From<std::net::AddrParseError> for WError {
    fn from(value: std::net::AddrParseError) -> Self {
        Self::ParseError(value.to_string())
    }
}

#[cfg(feature = "net")]
impl<T> From<tokio::sync::mpsc::error::SendError<T>> for WError {
    fn from(value: tokio::sync::mpsc::error::SendError<T>) -> Self {
        Self::NetError(value.to_string())
    }
}

impl From<clap::Error> for WError {
    fn from(value: clap::Error) -> Self {
        WError::ParseError(value.to_string())
    }
}

#[cfg(feature = "req")]
impl From<reqwest::Error> for WError {
    fn from(value: reqwest::Error) -> Self {
        WError::NetError(value.to_string())
    }
}


pub type WResult<T> = Result<T, WError>;